﻿using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.SceneManagement;

namespace Nirvana
{
    /// <summary>
    /// 默认Shader检测规则脚本，用于替换默认标准shader材质球,避免创建多份mat
    /// 注意：
    ///     规则文件必须存放在资源的父目录或同一级目录下。便于不同资源模块的管理。
    /// </summary>
    [CreateAssetMenu(fileName = "@DefaultShaderRule", menuName = "Nirvana/Asset/DefaultShaderRule")]
    public class DefaultShaderRule : ScriptableObject
    {
        /// <summary>
        /// 替换内置标准shader材质球
        /// </summary>
        /// 
        [Tooltip("Replace Default-Material")]
        [SerializeField]
        private BoolVariate default_material;

        [Tooltip("Replace Default-Particle")] //for Alpha Blended Premultiply
        [SerializeField]
        private BoolVariate default_particle;

        [Tooltip("Replace Default-ParticleSystem")]
        [SerializeField]
        private BoolVariate default_particleSystem;

        [Tooltip("Replace Sprites-Default")]
        [SerializeField]
        private BoolVariate default_sprite;

        public enum MatType
        {
            Standard = 0,
            Particle = 1,
            ParticleSystem = 2,
            Sprite = 3,
            Normal = 4,
        }
        static Material replacedStandardMat;
        static Material replacedSpriteMat;
        static Material replacedParticleSystemMat;
        static Dictionary<MatType, Material> typeAndMaterial;

        /// <summary>
        /// 返回当前配置脚本的存放目录
        /// </summary>
        /// <returns></returns>
        public string GetDirectorName()
        {
            string assetpath = AssetDatabase.GetAssetPath(this);
            return Path.GetDirectoryName(assetpath);
        }
       

        public void FixPrefabStandardShader(bool isReplace)
        {
            if((default_material.IsHasValue() && default_material.GetValue())
                || (default_particle.IsHasValue() && default_particle.GetValue())
                || (default_particleSystem.IsHasValue() && default_particleSystem.GetValue())
                || (default_sprite.IsHasValue() && default_sprite.GetValue()))
            {
                if(isReplace) InitReplacedMats();

                Scene newScene = EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single);

                string findpath = GetDirectorName();
                bool needSave = false;
                GameObject prefabObj = null;

                string[] prefabGUIDArray = AssetDatabase.FindAssets("t:prefab", new string[] { findpath });
                for (int i = 0; i < prefabGUIDArray.Length; i++)
                {
                    string path = AssetDatabase.GUIDToAssetPath(prefabGUIDArray[i]);
                    var asset = AssetDatabase.LoadAssetAtPath<GameObject>(path);
                    if (asset == null)
                    {
                        continue;
                    }

                    prefabObj = PrefabUtility.InstantiatePrefab(asset, SceneManager.GetActiveScene()) as GameObject;
                    var cancel = EditorUtility.DisplayCancelableProgressBar("FixPrefabStandardShader", "Prefab -> " + prefabObj.name, i*1.0f / prefabGUIDArray.Length);
                    if (cancel)
                    {
                        break;
                    }
                    needSave = CheckAndReplaceObjectMats(ref prefabObj, isReplace);
                    if (needSave)
                    {
                        Debug.Log("###: default materail object path : " + path);
                        PrefabUtility.SaveAsPrefabAsset(prefabObj, path);
                    }
                    //EditorUtility.ClearProgressBar();
                    //EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single);
                }
                EditorUtility.ClearProgressBar();
                EditorSceneManager.CloseScene(newScene, true);
                EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single);
            }

        }


        private void InitReplacedMats()
        {
            typeAndMaterial = new Dictionary<MatType, Material>();
            typeAndMaterial.Add(MatType.Particle, LoadOrCreateDefaultMaterial("Assets/Resources/BuildInShader/Default_Particle.mat", "Legacy Shaders/Particles/Alpha Blended Premultiply"));
            typeAndMaterial.Add(MatType.ParticleSystem, LoadOrCreateDefaultMaterial("Assets/Resources/BuildInShader/Default_ParticleSystem.mat", "Particles/Standard Unlit"));
            typeAndMaterial.Add(MatType.Sprite, LoadOrCreateDefaultMaterial("Assets/Resources/BuildInShader/Default_Sprite.mat", "Sprites/Default"));
            typeAndMaterial.Add(MatType.Standard, LoadOrCreateDefaultMaterial("Assets/Resources/BuildInShader/Default_Mat.mat","Standard"));
        }

        private Material LoadOrCreateDefaultMaterial(string materialPath,string defaultShader)
        {
            Material defaultMaterial = AssetDatabase.LoadAssetAtPath(materialPath, typeof(Material)) as Material;
            if (defaultMaterial == null)
            {
                if (!Directory.Exists(materialPath)) Directory.CreateDirectory(Path.GetDirectoryName(materialPath));
                 defaultMaterial = new Material(Shader.Find(defaultShader));
                AssetDatabase.CreateAsset(defaultMaterial, materialPath);
                AssetDatabase.Refresh();
            }
            return defaultMaterial;
        }

        private MatType GetReplacedMatType(Material srcMat)
        {
            if (srcMat == null)
            {
                return MatType.Normal;
            }
            else if (srcMat.name.Equals("Default-ParticleSystem")|| srcMat.name.Equals("Default_ParticleSystem"))
            {
                return MatType.ParticleSystem;
            }
            else if (srcMat.name.Equals("Default-Particle") || srcMat.name.Equals("Default_Particle"))
            {
                return MatType.Particle;
            }
            else if (srcMat.name.Equals("Sprites-Default"))
            {
                return MatType.Sprite;
            }
            else if (srcMat.name.Equals("Default-Material") || srcMat.name.Contains("No Name"))
            {
                return MatType.Standard;
            }
            return MatType.Normal;
        }

        private bool CheckAndReplaceObjectMats(ref GameObject obj,bool isReplace)
        {

            bool needSave = false;

            if (default_material.GetValue() && default_sprite.GetValue())
            {
                Renderer[] allRender = obj.GetComponentsInChildren<Renderer>(true);
                for (int j = 0; j < allRender.Length; j++)
                {
                    Material[] srcMats = allRender[j].sharedMaterials;
                    bool needSaveMats = false;
                    if (srcMats != null)
                    {
                        for (int k = 0; k < srcMats.Length; k++)
                        {
                            var type = GetReplacedMatType(srcMats[k]);
                            if (type != MatType.Normal)
                            {
                                needSaveMats = true;
                                needSave = true;
                                if(isReplace) srcMats[k] = typeAndMaterial[type];
                            }
                        }
                        if (needSaveMats)
                        {
                            allRender[j].sharedMaterials = isReplace? srcMats : new Material[allRender[j].sharedMaterials.Length];
                        }
                    }
                }
            }

            if (default_material.GetValue() && default_sprite.IsHasValue() == false)
            {
                Renderer[] allRender = obj.GetComponentsInChildren<Renderer>(true);
                for (int j = 0; j < allRender.Length; j++)
                {
                    Material[] srcMats = allRender[j].sharedMaterials;
                    bool needSaveMats = false;
                    if (srcMats != null)
                    {
                        for (int k = 0; k < srcMats.Length; k++)
                        {
                            var type = GetReplacedMatType(srcMats[k]);
                            if (type == MatType.Standard)
                            {
                                needSaveMats = true;
                                needSave = true;
                                if (isReplace) srcMats[k] = typeAndMaterial[type];
                            }
                        }
                        if (needSaveMats)
                        {
                            allRender[j].sharedMaterials = isReplace ? srcMats : new Material[allRender[j].sharedMaterials.Length];
                        }
                    }
                }
            }

            if (default_sprite.GetValue() && default_material.IsHasValue() == false)
            {
                Renderer[] allRender = obj.GetComponentsInChildren<Renderer>(true);
                for (int j = 0; j < allRender.Length; j++)
                {
                    Material[] srcMats = allRender[j].sharedMaterials;
                    bool needSaveMats = false;
                    if (srcMats != null)
                    {
                        for (int k = 0; k < srcMats.Length; k++)
                        {
                            var type = GetReplacedMatType(srcMats[k]);
                            if (type == MatType.Sprite)
                            {
                                needSaveMats = true;
                                needSave = true;
                                if (isReplace) srcMats[k] = typeAndMaterial[type];
                            }
                        }
                        if (needSaveMats)
                        {
                            allRender[j].sharedMaterials = isReplace ? srcMats : new Material[allRender[j].sharedMaterials.Length];
                        }
                    }
                }
            }

            if (default_particleSystem.GetValue() || default_particle.GetValue())
            {
                ParticleSystemRenderer[] allParticleSystemRenderers = obj.GetComponentsInChildren<ParticleSystemRenderer>(true);

                for (int j = 0; j < allParticleSystemRenderers.Length; j++)
                {
                    Material[] srcMats = allParticleSystemRenderers[j].sharedMaterials;
                    if (srcMats != null)
                    {
                        bool needSaveMats = false;
                        for (int k = 0; k < srcMats.Length; k++)
                        {
                            var type = GetReplacedMatType(srcMats[k]);
                            if (type == MatType.ParticleSystem || type == MatType.Particle)
                            {
                                needSaveMats = true;
                                needSave = true;
                                if (isReplace) srcMats[k] = typeAndMaterial[type];
                            }
                        }
                        if (needSaveMats)
                        {
                            allParticleSystemRenderers[j].sharedMaterials = isReplace ? srcMats : new Material[allParticleSystemRenderers[j].sharedMaterials.Length];
                            if(!isReplace) allParticleSystemRenderers[j].enabled = false;
                        }
                    }

                    Material trailMat = allParticleSystemRenderers[j].trailMaterial;
                    var type1 = GetReplacedMatType(trailMat);
                    if (type1 != MatType.Normal)
                    {
                        needSave = true;
                        allParticleSystemRenderers[j].trailMaterial = isReplace? typeAndMaterial[type1] : null;
                    }
                }
            }


            return needSave;
        }
    }
}

